﻿/*
-----------------------------------------------------------------------------
This source file is part of Cell Cloud.

Copyright (c) 2009-2011 Cell Cloud Team - cellcloudproject@gmail.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/

#include "TestSuite.h"

LoggerManager* gLoggerManager = NULL;

//-----------------------------------------------------------------------
GlobalConfig::GlobalConfig(void)
{
	std::cout << "test setup" << std::endl;

	if (LoggerManager::getSingletonPtr() == NULL)
	{
		gLoggerManager = CELL_NEW LoggerManager();
		gLoggerManager->createLogger("test_packet.log", true, true);
	}
}
//-----------------------------------------------------------------------
GlobalConfig::~GlobalConfig(void)
{
	std::cout << "test teardown" << std::endl;

	if (gLoggerManager != NULL)
	{
		CELL_DELETE gLoggerManager;
		gLoggerManager = NULL;
	}
}


//-----------------------------------------------------------------------
PacketTester::PacketTester(void)
{
}
//-----------------------------------------------------------------------
PacketTester::~PacketTester(void)
{
}
//-----------------------------------------------------------------------
void PacketTester::testSegment(void)
{
	using cell::byte;

	byte expectedTag[PSL_TAG] = {0x0};
	memcpy(expectedTag, "CELL", PSL_TAG);

	const uint16 expectedMajor = randomVersionNumber(), expectedMinor = randomVersionNumber();

	const uint16 expectedSN = randomSequenceNumber();

	const char* bodyData = "Windows Azure offers an internet-scale hosting environment built on geographically distributed data centers. This hosting environment provides a runtime execution environment for managed code.";
	const uint expectedBodyLen = strlen(bodyData);
	byte* expectedBody = CELL_ALLOC_T(byte, expectedBodyLen, MEMCATEGORY_GENERAL);
	memcpy(expectedBody, bodyData, expectedBodyLen);

	Packet packet;
	packet.setTag(expectedTag);
	packet.setVersion(expectedMajor, expectedMinor);
	packet.setSequenceNumber(expectedSN);
	packet.setBody(expectedBody, expectedBodyLen);

	// 检查 Tag
	byte actualTag[PSL_TAG];
	packet.getTag(actualTag);
	for (uint i = 0; i < packet.getTagSegmentLength(); ++i)
	{
		BOOST_CHECK_EQUAL(expectedTag[i], actualTag[i]);
	}
	BOOST_CHECK_EQUAL(true, packet.compareTag(expectedTag));

	// 检查 Version
	uint16 actualMajor, actualMinor;
	packet.getVersion(&actualMajor, &actualMinor);
	BOOST_CHECK_EQUAL(expectedMajor, actualMajor);
	BOOST_CHECK_EQUAL(expectedMinor, actualMinor);

	// 检查 SN
	uint16 actualSN;
	packet.getSequenceNumber(&actualSN);
	BOOST_CHECK_EQUAL(expectedSN, actualSN);

	// 检查 Body
	uint actualBodyLen = packet.getBodyLength();
	BOOST_CHECK_EQUAL(expectedBodyLen, actualBodyLen);
	byte* actualBody = CELL_ALLOC_T(byte, actualBodyLen, MEMCATEGORY_GENERAL);
	actualBodyLen = packet.getBody(actualBody);
	BOOST_CHECK_EQUAL(expectedBodyLen, actualBodyLen);
	for (uint i = 0; i < actualBodyLen; ++i)
	{
		BOOST_CHECK_EQUAL(expectedBody[i], actualBody[i]);
	}
	CELL_FREE(actualBody, MEMCATEGORY_GENERAL);

	CELL_FREE(expectedBody, MEMCATEGORY_GENERAL);
}
//-----------------------------------------------------------------------
void PacketTester::testPack(void)
{
	using cell::byte;

	char tag[PSL_TAG] = {0x0};
	memcpy(tag, "CELL", PSL_TAG);

	const uint16 major = randomVersionNumber(), minor = randomVersionNumber();

	const uint16 sn = 109;

	const char* bodyData = "Windows Azure offers an internet-scale hosting environment built on geographically distributed data centers. This hosting environment provides a runtime execution environment for managed code.";
	const uint bodyLen = strlen(bodyData);	// 192 bytes
	char* body = CELL_ALLOC_T(char, bodyLen, MEMCATEGORY_GENERAL);
	memcpy(body, bodyData, bodyLen);

	byte expectedOutput[512] = {0x0};
	// tag
	memcpy(expectedOutput, tag, PSL_TAG);
	// version
	char versionNum[3] = {0x0};
	if (minor < 10)
		sprintf(versionNum, "0%d", minor);
	else
		sprintf(versionNum, "%d", minor);
	memcpy(expectedOutput + PSL_TAG, versionNum, 2);
	if (major < 10)
		sprintf(versionNum, "0%d", major);
	else
		sprintf(versionNum, "%d", major);
	memcpy(expectedOutput + PSL_TAG + 2, versionNum, 2);
	// sn
	memcpy(expectedOutput + PSL_TAG + PSL_VERSION, "0109", PSL_SN);
	// length
	memcpy(expectedOutput + PSL_TAG + PSL_VERSION + PSL_SN, "00000192", PSL_BODY_LENGTH);

	memcpy(expectedOutput + PSL_TAG + PSL_VERSION + PSL_SN + PSL_BODY_LENGTH, bodyData, bodyLen);
	const uint expectedLen = PSL_TAG + PSL_VERSION + PSL_SN + PSL_BODY_LENGTH + bodyLen;

	Packet packet(tag, sn, body, bodyLen, major, minor);

	byte actualOutput[512] = {0x0};
	// 测试
	uint actualLen = Packet::pack(actualOutput, &packet);

	// 数据长度检查
	BOOST_CHECK_EQUAL(expectedLen, actualLen);

	// 数据内容检查
	for (uint i = 0; i < actualLen; ++i)
	{
		BOOST_CHECK_EQUAL(expectedOutput[i], actualOutput[i]);
	}

	CELL_FREE(body, MEMCATEGORY_GENERAL);
}
//-----------------------------------------------------------------------
void PacketTester::testUnpack(void)
{
	using cell::byte;

	const char* bodyData = "Windows Azure offers an internet-scale hosting environment built on geographically distributed data centers. This hosting environment provides a runtime execution environment for managed code.";
	const uint bodyLen = strlen(bodyData);	// 192 bytes

	byte data[512] = "CELL1102010700000192";
	memcpy(data + 20, bodyData, bodyLen);
	const uint dataLen = 20 + bodyLen;

	byte expectedTag[PSL_TAG] = {'C','E','L','L'};
	const uint16 expectedMajor = 2, expectedMinor = 11;
	const uint16 expectedSN = 107;
	const uint expectedBodyLen = bodyLen;
	byte* expectedBody = CELL_ALLOC_T(byte, expectedBodyLen, MEMCATEGORY_GENERAL);
	memcpy(expectedBody, bodyData, expectedBodyLen);

	Packet* packet = CELL_NEW Packet();
	// 测试
	Packet::unpack(packet, data, dataLen);

	byte actualTag[PSL_TAG] = {0x0};
	uint16 actualMajor, actualMinor, actualSN;
	uint actualBodyLen;
	byte actualBody[512] = {0x0};

	// 检查 Tag
	packet->getTag(actualTag);
	for (uint i = 0; i < PSL_TAG; ++i)
	{
		BOOST_CHECK_EQUAL(expectedTag[i], actualTag[i]);
	}

	// 检查 Version
	packet->getVersion(&actualMajor, &actualMinor);
	BOOST_CHECK_EQUAL(expectedMajor, actualMajor);
	BOOST_CHECK_EQUAL(expectedMinor, actualMinor);

	// 检查 SN
	packet->getSequenceNumber(&actualSN);
	BOOST_CHECK_EQUAL(expectedSN, actualSN);

	// 检查 Body
	actualBodyLen = packet->getBody(actualBody);
	BOOST_CHECK_EQUAL(expectedBodyLen, actualBodyLen);
	for (uint i = 0; i < actualBodyLen; ++i)
	{
		BOOST_CHECK_EQUAL(expectedBody[i], actualBody[i]);
	}

	CELL_FREE(expectedBody, MEMCATEGORY_GENERAL);
	CELL_DELETE packet;
}
//-----------------------------------------------------------------------
void PacketTester::testAppendSubsegment(void)
{
	using cell::byte;

	byte expectedTag[PSL_TAG] = {'C','E','L','L'};
	const uint16 expectedMajor = randomVersionNumber(), expectedMinor = randomVersionNumber();
	const uint16 expectedSN = randomSequenceNumber();

	const char* data1 = "Windows Azure offers an internet-scale hosting environment built on geographically distributed data centers.";
	const uint expectedSubsegment1Len = strlen(data1);
	byte expectedSubsegment1[128] = {0x0};
	memcpy(expectedSubsegment1, data1, expectedSubsegment1Len);

	const char* data2 = "This hosting environment provides a runtime execution environment for managed code.";
	const uint expectedSubsegment2Len = strlen(data2);
	byte expectedSubsegment2[128] = {0x0};
	memcpy(expectedSubsegment2, data2, expectedSubsegment2Len);

	byte* actualSubsegment1 = NULL;
	uint actualSubsegment1Len = 0;
	byte* actualSubsegment2 = NULL;
	uint actualSubsegment2Len = 0;

	Packet* packet = CELL_NEW Packet(expectedTag, expectedSN, expectedMajor, expectedMinor);
	BOOST_CHECK_EQUAL(0, packet->getSubsegmentNum());
	// 测试子段长度
	BOOST_CHECK_EQUAL(0, packet->getSubsegmentLength(0));
	BOOST_CHECK_EQUAL(0, packet->getSubsegmentLength(7));

	packet->appendSubsegment(expectedSubsegment1, expectedSubsegment1Len);
	BOOST_CHECK_EQUAL(1, packet->getSubsegmentNum());
	actualSubsegment1Len = packet->getSubsegmentLength(0);
	BOOST_CHECK_EQUAL(expectedSubsegment1Len, actualSubsegment1Len);

	// 越界测试
	BOOST_CHECK_EQUAL(0, packet->getSubsegmentLength(1));

	// 测试子段数据
	actualSubsegment1 = CELL_ALLOC_T(byte, actualSubsegment1Len, MEMCATEGORY_GENERAL);
	actualSubsegment1Len = packet->getSubsegment(actualSubsegment1, 0);
	BOOST_CHECK_EQUAL(expectedSubsegment1Len, actualSubsegment1Len);
	for (uint i = 0; i < actualSubsegment1Len; ++i)
	{
		BOOST_CHECK_EQUAL(expectedSubsegment1[i], actualSubsegment1[i]);
	}
	CELL_FREE(actualSubsegment1, MEMCATEGORY_GENERAL);

	// 附加第二段数据
	packet->appendSubsegment(expectedSubsegment2, expectedSubsegment2Len);

	// 测试
	actualSubsegment1Len = packet->getSubsegmentLength(0);
	BOOST_CHECK_EQUAL(expectedSubsegment1Len, actualSubsegment1Len);
	actualSubsegment2Len = packet->getSubsegmentLength(1);
	BOOST_CHECK_EQUAL(expectedSubsegment2Len, actualSubsegment2Len);

	actualSubsegment2 = CELL_ALLOC_T(byte, actualSubsegment2Len, MEMCATEGORY_GENERAL);
	actualSubsegment2Len = packet->getSubsegment(actualSubsegment2, 1);
	BOOST_CHECK_EQUAL(expectedSubsegment2Len, actualSubsegment2Len);
	for (uint i = 0; i < actualSubsegment2Len; ++i)
	{
		BOOST_CHECK_EQUAL(expectedSubsegment2[i], actualSubsegment2[i]);
	}
	CELL_FREE(actualSubsegment2, MEMCATEGORY_GENERAL);

	CELL_DELETE packet;
}
//-----------------------------------------------------------------------
uint16 PacketTester::randomSequenceNumber(void)
{
	uint16 num = rand();
	if (num < 0 || num > 9999)
		return randomSequenceNumber();
	return num;
}
//-----------------------------------------------------------------------
uint16 PacketTester::randomVersionNumber(void)
{
	uint16 num = rand();
	if (num < 0 || num > 99)
		return randomVersionNumber();
	return num;
}



//-----------------------------------------------------------------------
PacketTestSuite::PacketTestSuite(void)
	: test_suite("PacketTestSuite")
{
	// add member function test cases to a test suite
	boost::shared_ptr<PacketTester> instance(new PacketTester());

	test_case* testSegment = BOOST_CLASS_TEST_CASE(&PacketTester::testSegment, instance);
	test_case* testPack = BOOST_CLASS_TEST_CASE(&PacketTester::testPack, instance);
	test_case* testUnpack = BOOST_CLASS_TEST_CASE(&PacketTester::testUnpack, instance);
	test_case* testAppendSubsegment = BOOST_CLASS_TEST_CASE(&PacketTester::testAppendSubsegment, instance);

	add(testSegment);
	add(testPack);
	add(testUnpack);
	add(testAppendSubsegment);
}
//-----------------------------------------------------------------------
PacketTestSuite::~PacketTestSuite(void)
{
}
